﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace CardMonitor.Utils
{
    class Reader
    {
        /// <summary>
        /// 获取错误信息
        /// </summary>
        /// <param name="st">错误代码</param>
        /// <returns>错误信息描述</returns>
        public static string GetErrMsg(int lg, int st)
        {
            byte[] msg = new byte[1024];
            int len = getErrMsg(st, lg, msg);
            return Encoding.Default.GetString(msg, 0, len);
        }

        /// <summary>
        /// 动态库名称
        /// </summary>
        private const string dllPath = "hc_icrf32.dll";

        #region 设备操作

        /// <summary>
        /// 连接读写器,使用于串口通信和USB口通信设备
        /// </summary>
        /// <param name="port"><para>当取值为 0～19 时, 表示串口 1～20</para>
        /// <para>当取值为 100 时,表示 USB 口通讯</para></param>
        /// <param name="baud">串口通信波特率, 取值 9600 ~ 115200 . 当 <paramref name="port"/>=100 时,此参数无用.</param>
        /// <returns>设备句柄,小于0时失败,返回错误代码</returns>
        [DllImport(dllPath)]
        public static extern IntPtr hc_init(short port, uint baud);

        /// <summary>
        /// 关闭读写器
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int hc_exit(IntPtr icdev);

        /// <summary>
        /// 读取设备硬件版本号
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="len">要读取的硬件版本号的长度, 范围 0 ~ 32. 当取值为 0 时,表示读取全部版本号. 其它值表示读取指定长度的版本号.</param>
        /// <param name="data_buffer">存放读取到的硬件版本号,最少分配32byte.</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int srd_ver(IntPtr icdev, short len, StringBuilder strVer);

        /// <summary>
        /// 打开指定编号的读写器,此函数只适用于 USB 通讯设备,可用于一台电脑连接多台设备的情况.
        /// </summary>
        /// <param name="number">读写器编号</param>
        /// <returns>设备句柄,小于0时失败,返回错误代码.</returns>
        /// <remarks>
        /// <para>首先使用 <see cref="Reader.hc_init(short, uint)"/> 打开设备</para>
        /// <para>然后再通过<see cref="Reader.set_usb_number(IntPtr, int)"/>设置设备编号后,可通过此方法打开指定编号的设备. </para>
        /// </remarks>
        [DllImport(dllPath)]
        public static extern IntPtr hc_init_usb(int number);

        /// <summary>
        /// 设置读写器编号,仅适用于USB通信设备
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="number">要设置的读写器编号, 取值 0 ~ 255.</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int set_usb_number(IntPtr icdev, int number);

        /// <summary>
        /// 获取读写器编号,仅适用于USB通信设备
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="number">读取到的读写器编号, 取值 0 ~ 255.</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int get_usb_number(IntPtr icdev, out int number);

        /// <summary>
        /// 连接读写器,仅适用于 TCP/IP 网络通信设备 
        /// </summary>
        /// <param name="ip">读写器的 IP 地址</param>
        /// <param name="loc_port">读写器的网络端口号</param>
        /// <returns>设备句柄,小于0时失败,返回错误代码.</returns>
        [DllImport(dllPath)]
        public static extern IntPtr hc_net_init(string ip, uint loc_port);

        /// <summary>
        /// 设置串口通信波特率
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="baud">要设置的串口波特率,取值 9600 ~ 115200. </param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int set_baud(IntPtr icdev, uint baud);

        /// <summary>
        /// 自动弹卡,仅适用于接触自弹式卡座
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int auto_pull(IntPtr icdev);

        /// <summary>
        /// 获取密码键盘输入的密码
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="voice">语音提示.
        /// <para>0 -- 无语音提示; 1 -- 请输入密码; 2 -- 请再输入一次; 3 -- 请再输入一次新密码; 4 -- 请再输入新密码;</para>
        /// </param>
        /// <param name="timeout">超时时间,单位为秒,范围 0 ~ 60.在此时间内没有按确认键将返回失败.</param>
        /// <param name="pin_len">获取到的密码长度</param>
        /// <param name="pin">获取到的密码</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int dv_getpin(IntPtr icdev, byte voice, byte timeout, out uint pin_len, StringBuilder pin);

        /// <summary>
        /// led灯控制
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="ledNumber">led灯编号, 取值 0 ~ 2</param>
        /// <param name="status">led灯状态, 0表示亮, 1表示灭</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int dv_led(IntPtr icdev, byte ledNumber, byte status);

        /// <summary>
        /// 获取二维码信息
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="timeout">超时时间,单位为秒,范围 0 ~ 60.在此时间内没有扫描到二维码将返回失败.</param>
        /// <param name="qblen">获取到的二维码信息<paramref name="qbdata"/>的长度</param>
        /// <param name="qbdata">获取到的二维码信息</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int dv_getQRcode(IntPtr icdev, byte timeout, out uint qblen, byte[] qbdata);

        /// <summary>
        /// 设置读写器的本机网络参数,设置成功后不会立即生效,需要重启设备.(仅适用于网络通信设备) 
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="loc_ip">读写器的ip地址</param>
        /// <param name="loc_port">读写器的网络端口号</param>
        /// <param name="gateway">读写器的设备网关</param>
        /// <param name="mask">读写器的子网掩码</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int dv_setlocnet(IntPtr icdev, string loc_ip, uint loc_port, string gateway, string mask);

        /// <summary>
        /// 设置读写器的服务器网络参数,设置成功后不会立即生效,需要重启设备(仅适用于网络通信设备).
        /// <para>当读写器为客户端模式使用此方法设置服务器的参数.</para>
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="server_ip">服务器的 ip 地址 </param>
        /// <param name="server_port">服务器的网络端口号 </param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int dv_setsernet(IntPtr icdev, string server_ip, uint server_port);

        /// <summary>
        /// 读取读写器的网络参数
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="mode">读取到的读写器的工作模式.
        /// <para>0 -- 被动模式,设备作为服务器,需要PC机发送指令到读写器.</para>
        /// <para>1 -- 主动读卡模式.设备作为客户端并主动读卡,然后把读到的卡数据发送至服务器.</para> 
        /// </param>
        /// <param name="loc_ip">读取到的设备ip地址</param>
        /// <param name="loc_port">读取到的设备网络端口号</param>
        /// <param name="gateway">读取到的设备网关</param>
        /// <param name="mask">读取到的设备子网掩码</param>
        /// <param name="server_ip">读取到的服务器ip地址</param>
        /// <param name="server_port">读取到的服务器端口号</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int dv_srdnet(IntPtr icdev, out byte mode, StringBuilder loc_ip, out uint loc_port, StringBuilder gateway, StringBuilder mask,
                                           StringBuilder server_ip, out uint server_port);

        /// <summary>
        /// 设置网络设备的 mac 地址,设置成功后不会立即生效,需要重启设备(仅适用于网络通信设备).
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="mac">要设置的新 mac 地址 </param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int dv_setnetmac(IntPtr icdev, StringBuilder mac);

        /// <summary>
        /// 读取网络设备的 mac 地址(仅适用于网络通信设备).
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="mac">读取到的读写器 mac 地址</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int dv_srdnetmac(IntPtr icdev, StringBuilder mac);

        /// <summary>
        /// 设置网络设备工作模式,设置成功后不会立即生效,需要重启设备(仅适用于网络通信设备).
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="mode">网络设备工作模式.
        /// <para>0 -- 被动模式,设备作为服务器,需要PC机发送指令到读写器.</para>
        /// <para>1 -- 主动读卡模式.设备作为客户端并主动读卡,然后把读到的卡数据发送至服务器.</para>
        /// </param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int dv_setnetmode(IntPtr icdev, byte mode);

        /// <summary>
        /// 设备重启.用于更改网络参数后远程重启设备(仅适用于网络通信设备).
        /// </summary>
        /// <param name="idcdev">连接读写器返回的设备句柄</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int dv_reset(IntPtr idcdev);

        /// <summary>
        /// 设置主动读卡模式参数(仅适用于网络通信设备) 
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="mode">主动读卡的模式.最高位表示蜂鸣及指示灯是否有效,1 为有效,0 为无效.其余位取值如下:
        /// <para>0 -- 读取非接触卡片 UID(4 字节/7 字节)</para>
        /// <para>1 -- 读取 M1 卡内扇区数据 </para>
        /// <para>2 -- 读取二代身份证物理 UID</para>
        /// </param>
        /// <param name="block_Adr">读取 M1 卡的数据起始块地址,当读取卡片 UID 时此参数无效. </param>
        /// <param name="block_Num">连续读取块的数量,当读取卡片 UID 时此参数无效. </param>
        /// <param name="_Key">读取块所在扇区的密码,当读取卡片 UID 时此参数无效. 
        /// <para>当读取的块号跨扇区时,需要保证所有扇区密码一致.</para></param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int dv_setnetreadcard(IntPtr icdev, byte mode, byte block_Adr,
                                    byte block_Num, byte[] _Key);
        /// <summary>
        /// 读取主动读卡模式参数(仅适用于网络通信设备)
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="mode">读取到的读卡模式.最高位表示蜂鸣及指示灯是否有效,1 为有效,0 为无效.其余位取值如下:
        /// <para>0 -- 读取非接触卡片 UID(4 字节/7 字节)</para>
        /// <para>1 -- 读取 M1 卡内扇区数据 </para></param>
        /// <param name="block_Adr">读取到的 M1 卡数据起始块地址,当 mode = 0 时此参数无效</param>
        /// <param name="block_Num">读取到的连续读取块的数量,当 mode = 0 时此参数无效</param>
        /// <param name="_Key">读取到的 M1 卡密码.</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int dv_srdnetreadcard(IntPtr icdev, out byte mode, out byte block_Adr,
                                    out byte block_Num, byte[] _Key);
        /// <summary>
        /// LCD清屏
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int lcd_clear(IntPtr icdev);

        /// <summary>
        /// LCD显示,使用硬件自带字库.
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="line">要显示字符所在的行,取值0或1</param>
        /// <param name="offset">要显示字符所在的列,范围 0 ~ 15</param>
        /// <param name="disp_buf">要显示的字符数据</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int lcd_display(IntPtr icdev, byte line, byte offset, byte[] disp_buf);

        /// <summary>
        /// LCD显示屏背光设置
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="flag">0 -- 关闭背光; 1 -- 打开背光.</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int lcd_backlight(IntPtr icdev, byte flag);

        /// <summary>
        /// LCD显示,使用动态库自带字库.
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="line">要显示字符所在的行,取值0或1</param>
        /// <param name="offset">要显示字符所在的列,范围 0 ~ 15</param>
        /// <param name="len">显示数据的长度,英文字母占 1 个长度,中文占 2 个长度 </param>
        /// <param name="disp_buf">要显示的字符数据</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int lcd_display_zk(IntPtr icdev, byte line, byte offset, byte len, byte[] disp_buf);

        /// <summary>
        /// 获取用户卡槽(大卡座)是否有卡 
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="state"> 插卡状态. 0 -- 无卡; 1 -- 有卡 </param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int get_status(IntPtr icdev, out short state);

        /// <summary>
        /// 读写器蜂鸣
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="time">蜂鸣时间, 值范围 0-255（单位 10ms）</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int dv_beep(IntPtr icdev, short time);

        /// <summary>
        /// 向读写器的备注区中写入数据
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="offset">写入的起始偏移地址, 范围: 0 ~ 999 </param>
        /// <param name="len">要写入的数据长度, 范围: 1 ~ 1000 </param>
        /// <param name="data_buffer">要写入的数据</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int swr_eeprom(IntPtr icdev, short offset, short len, byte[] data_buffer);

        /// <summary>
        /// 读取读写器备注区中的数据
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="offset">读取的起始偏移地址, 范围: 0 ~ 999 </param>
        /// <param name="len">读取的的数据长度, 范围: 1 ~ 1000 </param>
        /// <param name="data_buffer">存放读取到的数据</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int srd_eeprom(IntPtr icdev, short offset, short len, byte[] data_buffer);

        /// <summary>
        /// 读取产品序列号
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="len">序列号长度,默认16</param>
        /// <param name="data_buffer">读取到的序列号,最少分配16byte.</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int srd_snr(IntPtr icdev, short len, StringBuilder data_buffer);

        /// <summary>
        /// 选择协议, 对于多协议读写器, 操作卡片前需要选择卡片相应的协议才可操作卡片
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="protype">协议类型. 0: TypeA; 1: TypeB; 2: ICODE; 3: Felica</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_select_protocol(IntPtr icdev, byte protype);

        /// <summary>
        /// 读写器主动/被动模式切换
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="rw">0 -- 读取读写器当前模式, 1 -- 根据ap参数切换读写器模式</param>
        /// <param name="rap">读取到的读写器模式(rw = 1 时此参数无效), 0 -- 被动模式, 1 -- 主动模式</param>
        /// <param name="wap">要切换的读写器模式(rw = 0 时此参数无效), 0 -- 被动模式, 1 -- 主动模式</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int dv_convert(IntPtr icdev, byte rw, out byte rap, byte wap);
        #endregion

        #region 工具方法

        /// <summary>
        /// 获取错误代码所表示的错误信息
        /// </summary>
        /// <param name="st">错误代码</param>
        /// <param name="lg">语言. 0 -- 简体中文; 1 -- English.</param>
        /// <param name="byMsg"></param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        private static extern int getErrMsg(int st, int lg, byte[] byMsg);

        /// <summary>
        /// 使用指定的密钥对数据进行 Des 算法加密 
        /// </summary>
        /// <param name="key">用于加密的密钥,长度必须为 8 byte</param>
        /// <param name="ptrSource">要被加密的数据.</param>
        /// <param name="msgLen"><paramref name="ptrSource"/>的字节长度,必须为 8 的倍数</param>
        /// <param name="ptrDest">加密后的密文, 长度为<paramref name="msgLen"/></param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int ic_encrypt(byte[] key, byte[] ptrSource, ushort msgLen, byte[] ptrDest);

        /// <summary>
        /// 使用指定的密钥对密文数据进行 Des 算法解密 
        /// </summary>
        /// <param name="key">用于解密的密钥,长度必须为 8 </param>
        /// <param name="ptrSource">要被解密的数据</param>
        /// <param name="msgLen"><paramref name="ptrSource"/>的字节长度,必须为 8 的倍数</param>
        /// <param name="ptrDest">解密后的数据, 长度为<paramref name="msgLen"/></param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int ic_decrypt(byte[] key, byte[] ptrSource, ushort msgLen, byte[] ptrDest);

        /// <summary>
        /// 将每两个16进制asc码字符转换成一个16进制数据.如将字符串“a1a2a3a4a5” 转换为数组{0xa1,0xa2,0xa3,0xa4,0xa5}
        /// </summary>
        /// <param name="asc">要转换的数据</param>
        /// <param name="hex">存放转换后的数据, 长度为<paramref name="asc"/>的一半.</param>
        /// <param name="pair_len"><paramref name="asc"/>的实际长度,必须为偶数</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int asc_hex(string asc, byte[] hex, int pair_len);

        /// <summary>
        /// 将 16 进制数据转换为对应的16进制 asc 字符串,如将数组 {0xa1,0xa2,0xa3,0xa4,0xa5}转换为字符串“a1a2a3a4a5” 
        /// </summary>
        /// <param name="hex">要转换的数据</param>
        /// <param name="asc">转换后的数据, 长度为<paramref name="length"/> * 2.</param>
        /// <param name="length">要转换的数据<paramref name="hex"/>的字节长度</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int hex_asc(byte[] hex, StringBuilder asc, int length);

        /// <summary>
        /// 检测用户卡槽中插入的卡片类型
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <returns>返回卡片类型, 具体请查看《IC 卡类型代码》文档。小于0失败.</returns>
        [DllImport(dllPath)]
        public static extern int chk_card(IntPtr icdev);


        /// <summary>
        /// 设置读写器为脱机模式,设置成功后读写器将不会接收任何指令
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int dv_offline(IntPtr icdev);

        /// <summary>
        /// 设置读写器校验方式
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="type">0 -- CRC;  1 -- BCC.</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int dv_set_chek_type(IntPtr icdev, byte type);


        [DllImport(dllPath)]
        public static extern int aes_encode(byte[] iv, byte[] key, byte[] input, byte[] output, int inputlength);
        [DllImport(dllPath)]
        public static extern int aes_decode(byte[] iv, byte[] key, byte[] input, byte[] output, int inputlength);

        [DllImport(dllPath)]
        public static extern int aes_cbc_encrypt(byte[] iv, byte[] key, byte[] input, int inputlength, byte[] output);
        [DllImport(dllPath)]
        public static extern int aes_cbc_decrypt(byte[] iv, byte[] key, byte[] input, int inputlength, byte[] output);


        #endregion

        #region ISO14443 TypeA/S50/S70

        /// <summary>
        /// 将 RF（射频 13.56MHz）先关闭一段时间后再重新打开, 此操作会让所有在天线区域的卡片都回到初始状态.
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Msec"> 复位场强射频信号时间 ( 1~ 500ms); 0 —- 关闭射频场强信号 </param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_reset(IntPtr icdev, ushort _Msec);

        /// <summary>
        /// 向ISO14443 TypeA标准的卡片发出请求命令,开始操作一张新卡片时需要执行该函数
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Mode">寻卡模式.取值如下  
        /// <para>0 -- IDLE mode, 只有处在 IDLE 状态的卡片才响应读写器的命令,配合<see cref="Reader.rf_halt(IntPtr)"/>可防止卡片反复操作.</para>
        /// <para>1 -- ALL mode, 处在 IDLE 状态和 HALT 状态的卡片都将响应读写器的命令</para>
        /// </param>
        /// <param name="TagType">返回卡片类型代码. 
        /// <para>0x0004 -- Mifare std. 1k(S50); 0x0002 -- Mifare std. 4k(S70);  0x0044 -- UltraLight; 0x0010 -- MIFARE LIGHT; </para>
        /// <para>0x0008 -- MIFARE PRO;  0x00B4 -- MIFARE PLUS; 0x0344 -- DESFIRE; 0x0005 -- FM005; 0x3300 --  SHC1102</para>
        /// </param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_request(IntPtr icdev, byte _Mode, out short TagType);

        /// <summary>
        /// 防冲突. 激活读写器的防冲突队列.如果有几张 mifare 卡片在感应区内,将会选择一张卡片,并返回卡片的序列号.
        /// <para><see cref="Reader.rf_request(IntPtr, byte, out short)"/>之后调用此方法</para>
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Bcnt">默认0</param>
        /// <param name="_Snr">返回的卡片序列号</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_anticoll(IntPtr icdev, byte _Bcnt, out uint _Snr);

        /// <summary>
        /// 选择指定序列号的卡片,将卡片的容量返回给 PC 机.
        /// <para><see cref="Reader.rf_anticoll(IntPtr, byte, out uint)"/>之后调用此方法选择卡片</para>
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Snr"><see cref="Reader.rf_anticoll(IntPtr, byte, out uint)"/>返回的卡片序列号</param>
        /// <param name="_Size">返回的卡片容量.目前该值不能使用 </param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_select(IntPtr icdev, uint _Snr, out byte _Size);

        /// <summary>
        /// ISO14443 TypeA标准的卡片寻卡并返回卡片的序列号.它可以完成<see cref="Reader.rf_request(IntPtr, byte, out short)"/>、<see cref="Reader.rf_anticoll(IntPtr, byte, out uint)"/> 
        /// 和 <see cref="Reader.rf_select(IntPtr, uint, out byte)"/>  3 个方法的功能,适用于 4 字节序列号的卡片. 
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Mode">寻卡模式.取值如下  
        /// <para>0 -- IDLE mode, 只有处在 IDLE 状态的卡片才响应读写器的命令,配合<see cref="Reader.rf_halt(IntPtr)"/>可防止卡片反复操作.</para>
        /// <para>1 -- ALL mode, 处在 IDLE 状态和 HALT 状态的卡片都将响应读写器的命令</para>
        /// </param>
        /// <param name="_Snr">返回 4 byte 的卡片序列号</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_card(IntPtr icdev, byte _Mode, out uint _Snr);

        /// <summary>
        /// 二次防冲突. 7 字节序列号卡片需要进行二次防冲突及二次选卡
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Bcnt">默认为0</param>
        /// <param name="_Snr"> 返回二次冲突返回的序列号. 
        /// <para><see cref="Reader.rf_anticoll(IntPtr, byte, out uint)"/>返回的序列号低三字节同此序列号(4 字节)组成卡片的 7 字节序列号.</para>
        /// </param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_anticoll2(IntPtr icdev, byte _Bcnt, out uint _Snr);

        /// <summary>
        /// 二次选择卡片.<see cref="Reader.rf_anticoll2(IntPtr, byte, out uint)"/>之后调用.
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Snr"><see cref="Reader.rf_anticoll2(IntPtr, byte, out uint)"/>返回的序列号.</param>
        /// <param name="_Size">返回的卡片容量,目前不能使用.</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_select2(IntPtr icdev, uint _Snr, out byte _Size);

        /// <summary>
        /// ISO14443 TypeA标准的卡片寻卡并返回卡片的序列号.此函数可自动判断卡片序列号的长度.
        /// <para>当卡片 为 4 字节序列号时它集成了<see cref="Reader.rf_request(IntPtr, byte, out short)"/>、
        /// <see cref="Reader.rf_anticoll(IntPtr, byte, out uint)"/> 及 <see cref="Reader.rf_select(IntPtr, uint, out byte)"/> 3 个函数的功能;</para> 
        /// <para>当为 7 字节序列号的卡片时还集成了 <see cref="Reader.rf_anticoll2(IntPtr, byte, out uint)"/> 和 <see cref="Reader.rf_select2(IntPtr, uint, out byte)"/> 5 个函数的功能.</para> 
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Mode">寻卡模式.取值如下  
        /// <para>0 -- IDLE mode, 只有处在 IDLE 状态的卡片才响应读写器的命令,配合<see cref="Reader.rf_halt(IntPtr)"/>可防止卡片反复操作.</para>
        /// <para>1 -- ALL mode, 处在 IDLE 状态和 HALT 状态的卡片都将响应读写器的命令</para>
        /// </param>
        /// <param name="_Snr">返回的卡片序列号</param>
        /// <param name="snrlen">返回的卡片序列号长度.</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_scard(IntPtr icdev, byte _Mode, byte[] _Snr, out byte snrlen);

        /// <summary>
        /// ISO14443 TypeA标准的卡片寻卡并返回卡片的序列号. 它集成了 <see cref="Reader.rf_request(IntPtr, byte, out short)"/>、<see cref="Reader.rf_anticoll(IntPtr, byte, out uint)"/>、
        /// <see cref="Reader.rf_select(IntPtr, uint, out byte)"/>、<see cref="Reader.rf_anticoll2(IntPtr, byte, out uint)"/> 
        /// 及 <see cref="Reader.rf_select2(IntPtr, uint, out byte)"/> 5 个函数的功能,此函数仅用于 7 字节序列号的卡片.
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Mode">寻卡模式.取值如下  
        /// <para>0 -- IDLE mode, 只有处在 IDLE 状态的卡片才响应读写器的命令,配合<see cref="Reader.rf_halt(IntPtr)"/>可防止卡片反复操作.</para>
        /// <para>1 -- ALL mode, 处在 IDLE 状态和 HALT 状态的卡片都将响应读写器的命令</para>
        /// </param>
        /// <param name="_Snr">返回的7字节卡片序列号</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_card_7uid(IntPtr icdev, byte _Mode, byte[] _Snr);

        /// <summary>
        /// ISO14443 TypeA标准的卡片寻卡并返回卡片的16进制 asc 字符串格式的序列号. 它集成了 <see cref="Reader.rf_request(IntPtr, byte, out short)"/>、<see cref="Reader.rf_anticoll(IntPtr, byte, out uint)"/>、
        /// <see cref="Reader.rf_select(IntPtr, uint, out byte)"/>、<see cref="Reader.rf_anticoll2(IntPtr, byte, out uint)"/> 
        /// 及 <see cref="Reader.rf_select2(IntPtr, uint, out byte)"/> 5 个函数的功能,此函数仅用于 7 字节序列号的卡片.
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Mode">寻卡模式.取值如下  
        /// <para>0 -- IDLE mode, 只有处在 IDLE 状态的卡片才响应读写器的命令,配合<see cref="Reader.rf_halt(IntPtr)"/>可防止卡片反复操作.</para>
        /// <para>1 -- ALL mode, 处在 IDLE 状态和 HALT 状态的卡片都将响应读写器的命令</para>
        /// </param>
        /// <param name="_Snr">返回的16进制 asc 字符串格式的序列号</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_card_7uid_hex(IntPtr icdev, byte _Mode, StringBuilder _Snr);

        /// <summary>
        /// 终止ISO14443 TypeA标准的卡片. 卡片的所有操作完成之后调用此方法将卡片设为"Halt"状态
        /// <para>当寻卡模式为 0 时, 需要将卡片拿开重新放置在读写器上再调用 <see cref="Reader.rf_request(IntPtr, byte, out short)"/> 方法时读写器才能够再次操作该卡片. </para>
        /// <para>当寻卡模式为 1 时, 需要调用 <see cref="Reader.rf_request(IntPtr, byte, out short)"/> 方法时读写器才能够再次操作该卡片. </para>
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_halt(IntPtr icdev);

        /// <summary>
        /// 向读写器装载指定扇区的密码（覆盖原有的数据,不与卡片进行通讯). 读写器中有 16 个扇区的密码（0 ~ 15）,每个扇区有两组密码(KEY A 和 KEY B) 
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Mode">装载密码类型, 取值如下:
        /// <para>0 -- 装载 KeyA</para>
        /// <para>4 -- 装载 KeyB </para></param>
        /// <param name="_SecNr">装载密码的扇区号(0～15) </param>
        /// <param name="_NKey">装载的 6 字节密码.</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_load_key(IntPtr icdev, byte _Mode, byte _SecNr, byte[] _NKey);

        /// <summary>
        /// 向读写器装载指定扇区的密码（覆盖原有的数据,不与卡片进行通讯). 读写器中有 16 个扇区的密码（0 ~ 15）,每个扇区有两组密码(KEY A 和 KEY B) 
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Mode">装载密码类型, 取值如下:
        /// <para>0 -- 装载 KeyA</para>
        /// <para>4 -- 装载 KeyB </para></param>
        /// <param name="_SecNr">装载密码的扇区号(0～15) </param>
        /// <param name="_NKey">装载的 12 位 16 进制asc格式字符串密码.</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_load_key_hex(IntPtr icdev, byte _Mode, byte _SecNr, string _NKey);

        /// <summary>
        /// 验证指定扇区的密码, 此方法将与读写器中装载的密码(同一扇区)比较是否一致.如果密码与读写器中装载的密码（可用 <see cref="Reader.rf_load_key(IntPtr, byte, byte, byte[])"/> 方法装载）相匹配,则密码验证通过.
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Mode">验证的密码类型, 取值如下:
        /// <para>0 -- 用 KEY A 验证</para>
        /// <para>4 -- 用 KEY B 验证</para></param>
        /// <param name="_SecNr">要验证的扇区</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_authentication(IntPtr icdev, byte _Mode, byte _SecNr);

        /// <summary>
        /// 验证卡片所要访问的指定块所在扇区的密码与读写器中装载的密码（指定扇区）是否一致.如果卡片的密码与读写器中的密码（可用 <see cref="Reader.rf_load_key(IntPtr, byte, byte, byte[])"/> 方法装载）相匹配,则密码验证通过.
        /// <para>此方法主要用于验证扇区号大于 15 的扇区.</para>
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Mode">验证的密码类型, 取值如下:
        /// <para>0 -- 用 KEY A 验证</para>
        /// <para>4 -- 用 KEY B 验证</para></param>
        /// <param name="KeyNr">指定读写器中的扇区号</param>
        /// <param name="Adr">要验证的块号</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_authentication_2(IntPtr icdev, byte _Mode, byte KeyNr, byte Adr);

        /// <summary>
        /// 验证指定块所在扇区的密码, 此函数不需要装载密码.
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Mode">验证的密码类型, 取值如下:
        /// <para>0 -- 用 KEY A 验证</para>
        /// <para>4 -- 用 KEY B 验证</para></param>
        /// <param name="_BlockNr">要验证密码的块号. 密码验证成功后,此块所在扇区内的所有块均可操作.</param>
        /// <param name="_Key"><paramref name="_BlockNr"/>所在扇区的密码, 6字节.</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_authentication_key(IntPtr icdev, byte _Mode, byte _BlockNr, byte[] _Key);

        /// <summary>
        /// 验证指定块所在扇区的密码( 16进制字符串格式 ), 此函数不需要装载密码.
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Mode">验证的密码类型, 取值如下:
        /// <para>0 -- 用 KEY A 验证</para>
        /// <para>4 -- 用 KEY B 验证</para></param>
        /// <param name="_BlockNr">要验证密码的块号. 密码验证成功后,此块所在扇区内的所有块均可操作.</param>
        /// <param name="_Key"><paramref name="_BlockNr"/>所在扇区的密码, 16进制字符串格式, 长度为 12.</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_authentication_key_hex(IntPtr icdev, byte _Mode, byte _BlockNr, string _Key);

        /// <summary>
        /// 读取指定块数据
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Adr">要读取数据的块号</param>
        /// <param name="_Data">读取到的数据,至少分配16字节空间</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_read(IntPtr icdev, byte _Adr, byte[] _Data);

        /// <summary>
        /// 读取指定块的数据,返回16进制字符串格式数据
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Adr">要读取数据的块号</param>
        /// <param name="_Data">读取到的32位16进制字符串格式数据.</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_read_hex(IntPtr icdev, byte _Adr, StringBuilder _Data);

        /// <summary>
        /// 向指定块中写入数据
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Adr">要写入数据的块号</param>
        /// <param name="_Data">要写入的数据,字节长度小于等于16</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_write(IntPtr icdev, byte _Adr, byte[] _Data);

        /// <summary>
        /// 向指定块中写入16进制字符串格式的数据
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Adr">要写入数据的块号</param>
        /// <param name="_Data">要写入的数据,长度必须为32</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_write_hex(IntPtr icdev, byte _Adr, string _Data);

        [DllImport(dllPath)]
        public static extern int rf_write_block0(IntPtr icdev, byte _Adr, byte[] _Data);

        /// <summary>
        /// 初始化块值, 对某一块进行值操作时使用的是特殊的数据结构, 如果要进行加减值操作, 需要进行初始化操作, 然后才可以读、减、加的操作 
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Adr">要初始化值的块号</param>
        /// <param name="_Value">要初始化的初始值.</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_initval(IntPtr icdev, byte _Adr, uint _Value);

        /// <summary>
        /// 读取指定块的值,此块必须为值
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Adr">要读取值的块号</param>
        /// <param name="_Value">读取到的值</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_readval(IntPtr icdev, byte _Adr, out uint _Value);

        /// <summary>
        /// 对指定的块进行增值操作
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Adr">要增值的块号</param>
        /// <param name="_Value">要增加的值</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_increment(IntPtr icdev, byte _Adr, uint _Value);

        /// <summary>
        /// 对指定的块进行减值操作
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_Adr">要减值的块号</param>
        /// <param name="_Value">要减少的值</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_decrement(IntPtr icdev, byte _Adr, uint _Value);

        /// <summary>
        /// 更改S50/S70卡片密码
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="_SecNr">要更改密码的扇区号</param>
        /// <param name="_KeyA">新的A密码</param>
        /// <param name="_B0"> 0 块的控制位,低三位(D2D1D0)对应为 C10,C20,C30.</param>
        /// <param name="_B1"> 1 块的控制位,低三位(D2D1D0)对应为 C11,C21,C31</param>
        /// <param name="_B2"> 2 块的控制位,低三位(D2D1D0)对应为 C12,C22,C32</param>
        /// <param name="_B3"> 3 块的控制位,低三位(D2D1D0)对应为 C13,C23,C33</param>
        /// <param name="_Bk">保留参数,默认为0.</param>
        /// <param name="_KeyB">新的B密码</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_changeb3(IntPtr icdev, byte _SecNr, byte[] _KeyA, byte _B0, byte _B1, byte _B2, byte _B3, byte _Bk, byte[] _KeyB);

        /*********** Mifare Plus *************************************************************************************************/

        /// <summary>
        /// 该命令用于SL0（Security Level 0，安全等级0）的PLUS CPU卡个人化数据，
        /// PLUS CPU卡出厂时的安全等级为SL0，该等级下，不需要任何验证就可以向卡里写数据，写入的数据是作为其它安全等级的初始值
        /// 执行该命令之前需要先进行寻卡激活卡片/>
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="addr">要写入数据的存储器地址</param>
        /// <param name="p_data">要写入的数据/AES密钥/配置字(16字节)</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_plus_write_perso(IntPtr icdev, ushort addr, byte[] p_data);

        /// <summary>
        /// 该命令用于SL0（Security Level 0，安全等级0）的PLUS CPU卡提交个人化数据.
        /// 方法<see cref="Reader.rf_plus_write_perso(IntPtr, ushort, byte[])"/>只是更新卡中的数据，但该数据还未生效，用户还不能直接使用。
        /// 执行该命令后，PLUS CPU卡的安全等级提高到SL1或者SL3（若是支持SL1的卡，则执行该命令后卡片安全等级提高到SL1；若是只支持SL0和SL3的卡，则执行该命令后卡片安全等级提高到SL3）
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_plus_commit_perso(IntPtr icdev);

        /// <summary>
        /// 在1级状态是和MIFARE系列卡一样操作的，此函数提供了一个专用的1级状态卡片认证功能，
        /// 可以在1级状态下实现严格的认证功能。（注意执行该命令卡片不要执行RATS操作）
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="authkey">6字节1级状态验证密钥</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_plus_auth_sl1(IntPtr icdev, byte[] authkey);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="addr"></param>
        /// <param name="aeskey"></param>
        /// <param name="blockNr"></param>
        /// <param name="keyMode"></param>
        /// <param name="sectorkey"></param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_plus_auth_sl2(IntPtr icdev, ushort addr, byte[] aeskey, byte blockNr, byte keyMode, byte[] sectorkey);

        /// <summary>
        /// 状态切换函数，执行该操作后，1级状态的卡片转换到2级。
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="authkey"></param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_plus_sl1_switch_to_sl2(IntPtr icdev, byte[] authkey);

        /// <summary>
        /// 状态切换函数，执行该操作后，1级状态的卡片转换到3级。
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="authkey"></param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_plus_sl1_switch_to_sl3(IntPtr icdev, byte[] authkey);

        /// <summary>
        /// 状态切换函数，执行该操作后，2级状态的卡片转换到3级。
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="authkey"></param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_plus_sl2_switch_to_sl3(IntPtr icdev, byte[] authkey);

        /// <summary>
        /// 该命令用于SL3 PLUS CPU卡的密钥验证
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="addr">AES密钥地址</param>
        /// <param name="p_data">AES密钥（16字节）</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_plus_first_auth(IntPtr icdev, ushort addr, byte[] p_data);

        /// <summary>
        /// 该命令用于SL3 PLUS CPU卡的跟随密钥验证，验证的密钥来自命令参数，
        /// 只有执行过<see cref="Reader.rf_plus_first_auth(IntPtr, ushort, byte[])"/>命令成功后才能使用该命令。
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="addr">AES密钥地址</param>
        /// <param name="p_data">AES密钥（16字节）</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_plus_follow_auth(IntPtr icdev, ushort addr, byte[] p_data);

        /// <summary>
        /// 该命令用于PLUS CPU卡通过首次验证后的使用过程中，复位读写计数器和验证等信息。
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_plus_sl3_reset_auth(IntPtr icdev);

        /// <summary>
        /// 该命令用于读取SL3的数据块，在读数据块之前必需成功执行一次密钥验证
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="read_mode">读模式
        /// <para>0x30: 命令有MAC; 数据密文; 回应无MAC</para>
        /// <para>0x31: 命令有MAC; 数据密文; 回应有MAC</para>
        /// <para>0x32: 命令有MAC; 数据明文; 回应无MAC</para>
        /// <para>0x33: 命令有MAC; 数据明文; 回应有MAC</para>
        /// <para>0x34: 命令无MAC; 数据密文; 回应无MAC</para>
        /// <para>0x35: 命令无MAC; 数据密文; 回应有MAC</para>
        /// <para>0x36: 命令无MAC; 数据明文; 回应无MAC</para>
        /// <para>0x37: 命令无MAC; 数据明文; 回应有MAC</para></param>
        /// <param name="start_addr">起始块号</param>
        /// <param name="block_num">读的块数量, 范围1～3</param>
        /// <param name="p_rx_data">读取到的数据</param>
        /// <param name="p_rx_lenght">读取数据的长度</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_plus_sl3_read(IntPtr icdev, byte read_mode, ushort start_addr, byte block_num, byte[] p_rx_data);

        /// <summary>
        /// 该命令用于写入SL3的数据块，在写数据块之前必需成功执行一次密钥验证。
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="write_mode">写模式
        /// <para>0xA0: 命令有MAC; 数据密文; 回应无MAC</para>
        /// <para>0xA1: 命令有MAC; 数据密文; 回应有MAC</para>
        /// <para>0xA2: 命令有MAC; 数据明文; 回应无MAC</para>
        /// <para>0xA3: 命令有MAC; 数据明文; 回应有MAC</para></param>
        /// <param name="start_addr">起始块号</param>
        /// <param name="block_num">写的块数量, 范围1～3</param>
        /// <param name="p_tx_data">写入的数据, 长度为<paramref name="block_num"/> * 16</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_plus_sl3_write(IntPtr icdev, byte write_mode, ushort start_addr,
            byte block_num, byte[] p_tx_data);

        /// <summary>
        /// 该命令用于对SL3的进行值操作 可将目标块的数据进行加减值操作后写入目标块
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="write_mode">值操作模式:   0xB7～加值; 0xB9～减值</param>
        /// <param name="addr">要操作的块号</param>
        /// <param name="data">要操作的值</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_plus_sl3_value_opr(IntPtr icdev, byte write_mode, ushort addr, uint data);

        #endregion

        #region ISO14443 TypeA/TypeB CPU/DesFire

        /// <summary>
        /// 非接触 TypeA cpu/DesFire卡复位, 在此之前需要先执行请求,防冲突及选卡操作激活卡片.
        /// <para>可查看<see cref="Reader.rf_request(IntPtr, byte, out short)"/>、<see cref="Reader.rf_anticoll(IntPtr, byte, out uint)"/>
        /// 及<see cref="Reader.rf_select(IntPtr, uint, out byte)"/>或<see cref="Reader.rf_card(IntPtr, byte, out uint)"/>方法</para>
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="rlen">卡片返回的复位应答信息的长度</param>
        /// <param name="rbuff">卡片返回的复位应答信息</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_pro_reset(IntPtr icdev, out byte rlen, byte[] rbuff);

        /// <summary>
        /// 非接触 TypeA cpu/DesFire卡复位,返回16进制字符串格式复位应答信息.在此之前需要先执行请求,防冲突及选卡操作激活卡片.
        /// <para>可查看<see cref="Reader.rf_request(IntPtr, byte, out short)"/>、<see cref="Reader.rf_anticoll(IntPtr, byte, out uint)"/>
        /// 及<see cref="Reader.rf_select(IntPtr, uint, out byte)"/>或<see cref="Reader.rf_card(IntPtr, byte, out uint)"/>方法</para>
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="rlen">卡片返回的复位应答信息(<paramref name="rbuff"/>)的长度</param>
        /// <param name="rbuff">卡片返回的16进制字符串格式复位应答信息</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_pro_reset_hex(IntPtr icdev, out byte rlen, StringBuilder rbuff);

        /// <summary>
        /// 向非接触式 TypeA/TypeB cpu/DesFire卡发送COS指令.
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="slen">要发送的COS指令<paramref name="sbuff"/>的字节长度</param>
        /// <param name="sbuff">要发送的COS指令</param>
        /// <param name="rbuff">卡片返回的应答信息,包含SW1,SW2.(DesFire没有SW1SW2)</param>
        /// <returns>卡片返回的应答信息长度,小于0失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_pro_send(IntPtr icdev, byte slen, byte[] sbuff, byte[] rbuff);

        /// <summary>
        /// 向非接触式 TypeA/TypeB cpu/DesFire卡发送16进制字符格式的COS指令
        /// 此函数指令长度及卡片返回响应信息长度(包含SW1, SW2)最多只有 255 byte.
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="sbuff">要发送的16进制字符串格式COS指令</param>
        /// <param name="rbuff">卡片返回的16进制字符格式应答信息,包含SW1,SW2.(DesFire没有SW1SW2)</param>
        /// <returns>卡片返回的应答信息<paramref name="rbuff"/>的长度,小于0失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_pro_send_hex(IntPtr icdev, string sbuff, StringBuilder rbuff);

        /// <summary>
        /// 向非接触式 TypeA/TypeB cpu/DesFire卡发送COS指令,此方法指令长度及卡片返回响应信息长度(包含SW1, SW2)可达 255 byte.
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="slen">要发送的COS指令<paramref name="sbuff"/>的字节长度</param>
        /// <param name="sbuff">要发送的COS指令</param>
        /// <param name="rbuff">卡片返回的应答信息,包含SW1,SW2.(DesFire没有SW1SW2)</param>
        /// <returns>卡片返回的应答信息长度,小于0失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_pro_send_l(IntPtr icdev, uint slen, byte[] sbuff, byte[] rbuff);

        /// <summary>
        /// 向非接触式 TypeA/TypeB cpu/DesFire卡发送16进制格式的COS指令
        /// 此方法指令长度及卡片返回响应信息长度(包含SW1, SW2)最多可达 65535 byte.
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="sbuff">要发送的16进制字符串格式COS指令</param>
        /// <param name="rbuff">卡片返回的16进制格式应答信息,包含SW1,SW2.(DesFire没有SW1SW2)</param>
        /// <returns>卡片返回的应答信息<paramref name="rbuff"/>的长度,小于0失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_pro_send_l_hex(IntPtr icdev, string sbuff, StringBuilder rbuff);

        /// <summary>
        /// 该函数用于解除TypeA CPU卡片激活状态,卡片进入 HALT 状态.向卡片传输任何指令,卡片都将不做任何响应,必须重新激活卡片.
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_pro_halt(IntPtr icdev);

        /// <summary>
        /// 非接触式 Cpu 卡 PPS 操作
        /// </summary>
        /// <param name="icdev">连接读写器返回的设备句柄</param>
        /// <param name="pps">0 -- 做支持的最高 PPS, 此时后面两个参数无用; 1 -- 按照后面两个参数(ds, dr)支持 PPS</param>
        /// <param name="dr">接收因子 DR, 有效为1，2，4，8，其余无效. pps参数为 0 时, 此参数无效</param>
        /// <param name="ds">发送因子 DS, 有效为1，2，4，8，其余无效. pps参数为 0 时, 此参数无效</param>
        /// <returns>等于 0 成功, 小于 0 失败.</returns>
        [DllImport(dllPath)]
        public static extern int rf_pro_pps(IntPtr icdev, byte pps, byte dr, byte ds);

        #endregion
    }
}
